package com.jml.二期.HashMap8;


public class JmlHashMap<K, V> implements JmlMap<K, V> {
    /**
     * 默认的加载因子为0.75
     */
    static final float DEFAULT_LOAD_FACTOR = 0.75f;
    /**
     * 加载因子    也就是阈值
     *
     * @serial
     */
    final float loadFactor;

    /**
     * hashMap中的存放所有的链表
     */
    transient Node<K, V>[] table;

    /**
     * 转红黑树阈值
     */
    static final int TREEIFY_THRESHOLD = 8;
    /**
     * 加载因子大小
     */
    int threshold;

    /**
     * 最大的容量
     */
    static final int MAXIMUM_CAPACITY = 1 << 30;
    /**
     * 默认的数组容量为16
     */
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

    public JmlHashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
    }

    @Override
    public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

    /**
     * 计算key的hash值 ， 如果key为空的情况下 存在第一个链表 数组[0]
     *
     * @param key
     * @return
     */
    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        // tab 其实就是数组中存放的所有的链表
        Node<K, V>[] tab;
        // 数组中链表的首节点
        Node<K, V> p;
        
        // n 就是我们当前数组的长度 i为当前key计算hash值存放的数组的index位置
        int n, i;
        // 如何当前我们的hashMap中的table中的数组为空的情况下 就开始扩容
        if ((tab = table) == null || (n = tab.length) == 0) {
            n = (tab = resize()).length;
        }
        //如果从数组中没有获取到对应的链表，就是开始赋值
        if ((p = tab[i = (n - 1) & hash]) == null) {
            tab[i] = newNode(hash, key, value, null);
        } else {
            // 当前key产生index冲突
            Node<K, V> e;
            K k;
            //相同key覆盖：如果hash值相等的情况下且key的内容也相等情况下  实现对我们的value覆盖
            if (p.hash == hash &&
                    ((k = p.key) == key || (key != null && key.equals(k)))) {
                e = p;
            } else {
                //不同key就新加节点
                //binCount 作用可以继续循环   ++binCount 在第一次循环的时候是否会执行
                for (int binCount = 0; ; ++binCount) {
                    // 链表表只有一个节点，z没有下一个节点
                    if ((e = p.next) == null) {
                        // hash值相同 ，可能值不同
                        // 链表的下一个节点为当前key 尾插法
                        p.next = newNode(hash, key, value, null);
                        // binCount0 TREEIFY_THRESHOLD 8 -1 7 0-7
                        //转化为红黑树条件
                        if (binCount >= TREEIFY_THRESHOLD - 1) {
                            treeifyBin(tab, hash);
                        }
                        // jdk7 hashMap插入 最新的放入到前面
                        break;
                    }
                    //覆盖：如果hash值相等的情况下且key的内容也相等情况下  实现对我们的value覆盖
                    if (e.hash == hash &&
                            ((k = e.key) == key || (key != null && key.equals(k)))) {
                        break;
                    }
                    p = e;
                }
            }
            //判断当前node 是否是红黑时节点，如果是红黑树节点情况下，就以红黑时规则存放
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                // 如果原来值为空的情况下
                if (!onlyIfAbsent || oldValue == null) {
                    e.value = value;
                }
                return oldValue;
            }

        }
 
        //  index=[(n - 1) & hash] jdk7 table.length-hash
        return null;
    }

    /**
     * 转红黑树存放
     *
     * @param tab
     * @param hash
     */
    private void treeifyBin(Node<K, V>[] tab, int hash) {
    }

    /**
     * 创建我们的node
     *
     * @param hash
     * @param key
     * @param value
     * @param
     * @return
     */
    private Node<K, V> newNode(int hash, K key, V value, Node next) {
        return new Node(hash, key, value, next);
    }

    /**
     * 对我们的数组实现扩容
     *
     * @return
     */
    private Node<K, V>[] resize() {
        // 获取原来table数组
        Node<K, V>[] oldTab = table;
        // 如果原来长度不为空的下，获取原来数组的长度
        int oldCap = (oldTab == null) ? 0 : oldTab.length;
        // 获取原来的加载因子阈值容量大小
        int oldThr = threshold;
        /**
         *  newCap新的容量 newThr 新的加载因子阈值
         */
        int newCap, newThr = 0;
        //  原来的大小>0情况下
        if (oldCap > 0) {
            // 如果原来的容量> 最大容量限制的情况下
            if (oldCap >= MAXIMUM_CAPACITY) {
                //加载因子的阈值为Integer最大值，不进行扩容
                threshold = Integer.MAX_VALUE;
                return oldTab;
                //新的容量是为原来的容量*2  并且原来的容量>默认16容量
            } else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                    oldCap >= DEFAULT_INITIAL_CAPACITY)
                // 新的加载因子容量为原来的加载因子值*2
            {   //实际存储容量
                newThr = oldThr << 1; // 双倍 threshold
            }
        } else if (oldThr > 0) {//进入这里表示oldCap还没有初始化为0
            // 新的容量为原来的加载因子阈值
            newCap = oldThr;
        } else {//进入这里表示oldCap还没有初始化，容器也没有初始化，就设置默认值
            // 新的容量为 16
            newCap = DEFAULT_INITIAL_CAPACITY;
            // 新的加载因子阈值为 16*0.75  第一次
            newThr = (int) (DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
        }
        // 如果新的加载因子值为0的情况下
        if (newThr == 0) {
            //ft= 新的容量*0.75
            float ft = (float) newCap * loadFactor;
            // 新的加载因子阈值=
            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float) MAXIMUM_CAPACITY ?
                    (int) ft : Integer.MAX_VALUE);
        }
        // 加载因子的阈值为 新的
        threshold = newThr;
        // 新的table=16 赋值给老的table
        Node<K, V>[] newTab = (Node<K, V>[]) new Node[newCap];
        table = newTab;
        return newTab;
    }

    //HashMap的底层采用单链表实现
    static class Node<K, V> {
        // hash值
        final int hash;
        // key
        final K key;
        // value
        V value;
        // 下一个节点
        Node<K, V> next;

        Node(int hash, K key, V value, Node<K, V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }

        public final K getKey() {
            return key;
        }

        public final V getValue() {
            return value;
        }

        @Override
        public final String toString() {
            return key + "=" + value;
        }


        public final V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }

    }

    public static void main(String[] args) {

        new JmlHashMap().add();
    }

    public void add() {
        JmlHashMap.Node[] table = null;
        // 新table=为16
        JmlHashMap.Node[] newTab = new JmlHashMap.Node[16];
        // 原来的table也是为16
        table = newTab;
        // 新table 数组为0 指向一个对象
        newTab[0] = new Node(0, 0, 0, null);
        System.out.println(table[0].value);
    }


}
